package com.chatplus.application.service.pay.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.chatplus.application.client.pay.domain.request.wechat.WeChatOrderPayRequest;
import com.chatplus.application.client.pay.domain.response.InternalPayQueryResponse;
import com.chatplus.application.client.pay.domain.response.InternalPayResponse;
import com.chatplus.application.client.pay.domain.response.wechat.WechatOrderPayResponse;
import com.chatplus.application.common.exception.BadRequestException;
import com.chatplus.application.common.logging.SouthernQuietLogger;
import com.chatplus.application.common.logging.SouthernQuietLoggerFactory;
import com.chatplus.application.constant.PayConstants;
import com.chatplus.application.domain.dto.AdminConfigDto;
import com.chatplus.application.domain.entity.account.WechatUserEntity;
import com.chatplus.application.domain.entity.pay.PayRequestEntity;
import com.chatplus.application.enumeration.PayChannelEnum;
import com.chatplus.application.enumeration.PayStatusEnum;
import com.chatplus.application.enumeration.SubModeEnum;
import com.chatplus.application.service.account.WechatUserService;
import com.chatplus.application.service.pay.PayChannelServiceProvider;
import com.chatplus.application.service.pay.impl.wechat.WeChatApiServiceProvider;
import com.chatplus.application.service.pay.impl.wechat.WeChatPayApiService;
import com.chatplus.application.util.ConfigUtil;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryV3Result;
import com.github.binarywang.wxpay.exception.WxPayException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Map;

/**
 * 支付渠道业务逻辑实现（微信支付）
 *
 * <p>Table: t_pay_channel - 支付渠道</p>
 *
 * @author developer
 */
@Service(PayChannelServiceProvider.SERVICE_NAME_PRE + "WEI_XIN")
public class WeChatChannelServiceImpl extends PayChannelService {
    private static final SouthernQuietLogger LOGGER = SouthernQuietLoggerFactory.getLogger(WeChatChannelServiceImpl.class);

    private final WeChatApiServiceProvider weChatApiServiceProvider;
    private final WechatUserService wechatUserService;

    public WeChatChannelServiceImpl(WeChatApiServiceProvider weChatApiServiceProvider,
                                    WechatUserService wechatUserService) {
        this.weChatApiServiceProvider = weChatApiServiceProvider;
        this.wechatUserService = wechatUserService;
    }

    private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss+08:00").withZone(ZoneId.of("Asia/Shanghai"));

    @Override
    public InternalPayResponse orderPay(PayRequestEntity payRequest, String subject) {
        InternalPayResponse paymentPayResponse = new InternalPayResponse();
        WeChatOrderPayRequest weChatOrderPayRequest = new WeChatOrderPayRequest();
        weChatOrderPayRequest.setPayTransactionId(payRequest.getPayTransactionId() + "");
        weChatOrderPayRequest.setMoney(payRequest.getTotalMoney());
        weChatOrderPayRequest.setSubject(subject);
        // 因为目前只有一个支付渠道，所以这里的appId、mchId、notifyUrl等参数都是写死的
        // weChatOrderPayRequest.setMchId(payRequest.getMrchCode());
        // weChatOrderPayRequest.setNotifyUrl(notifyUrl);
        // 微信H5支付
        weChatOrderPayRequest.setSceneType(payRequest.getSceneType());
        weChatOrderPayRequest.setPayerClientIp(payRequest.getClientIp());
        // 微信小程序支付需要设置用户openId
        if (SubModeEnum.WECHAT_JSAPI.equals(payRequest.getSubMode())) {
            WechatUserEntity wechatUser = wechatUserService.getByUserId(payRequest.getUserId());
            if (wechatUser == null) {
                throw new BadRequestException("请在微信内打开此页面并支付");
            }
            weChatOrderPayRequest.setUserId(wechatUser.getOpenId());
        }
        if (payRequest.getSubMode() == SubModeEnum.WECHAT_H5) {
            AdminConfigDto adminConfigDto = ConfigUtil.getAdminConfig();
            weChatOrderPayRequest.setReturnUrl(adminConfigDto.getBaseFrontendUrl() + "/mobile/profile");
        }
        // 设置订单超时时间
        weChatOrderPayRequest.setExpireTime(DTF.format(LocalDateTime.now().plusSeconds(180)));
        SubModeEnum subModeEnum = payRequest.getSubMode();
        WeChatPayApiService weChatPayApiService = weChatApiServiceProvider.getWeChatPayApiService(subModeEnum);
        WechatOrderPayResponse wechatOrderPayResponse = weChatPayApiService.orderPay(weChatOrderPayRequest);
        LOGGER.message("微信支付-返回参数")
                .context("payRequest", payRequest)
                .context("wechatOrderPayResponse", wechatOrderPayResponse)
                .info();
        if (wechatOrderPayResponse == null) {
            throw new BadRequestException("微信支付失败-请联系管理员处理");
        }
        switch (subModeEnum) {
            case WECHAT_JSAPI:
                paymentPayResponse = BeanUtil.copyProperties(wechatOrderPayResponse, InternalPayResponse.class);
                break;
            case WECHAT_H5:
                paymentPayResponse.setActionUrl(wechatOrderPayResponse.getH5Url());
                break;
            case WECHAT_NATIVE:
                paymentPayResponse.setActionUrl(wechatOrderPayResponse.getCodeUrl());
                break;
            default:
                break;
        }
        payRequest.setAppId(wechatOrderPayResponse.getAppId());
        return paymentPayResponse;
    }

    @Override
    public InternalPayQueryResponse queryOrderPay(PayRequestEntity payRequest) {
        InternalPayQueryResponse queryOrderPayResponse = null;
        try {
            SubModeEnum subModeEnum = payRequest.getSubMode();
            WeChatPayApiService weChatPayApiService = weChatApiServiceProvider.getWeChatPayApiService(subModeEnum);
            WxPayOrderQueryV3Result result = weChatPayApiService.queryOrderPay(payRequest);
            queryOrderPayResponse = new InternalPayQueryResponse();
            String tradeStatus = result.getTradeState();
            switch (tradeStatus) {
                case PayConstants.Wechat.TRADE_SUCCESS:
                    String successTime = result.getSuccessTime();
                    Instant payTime = ObjectUtil.defaultIfEmpty(successTime,
                            () -> DateUtil.parse(successTime).toInstant(), Instant.now());
                    queryOrderPayResponse.setPaySuccessAt(payTime);
                    queryOrderPayResponse.setPayStatusEnum(PayStatusEnum.SUCCESS);
                    String payerInfo = StringUtils.trimToEmpty(result.getPayer().getOpenid());
                    String bankType = result.getBankType();
                    queryOrderPayResponse.setTradeTransactionId(result.getTransactionId());
                    queryOrderPayResponse.setPayerInfo(payerInfo + "|" + bankType);
                    break;
                // 如果交易关闭|结束，不处理支付结果，但是不报错，消费掉队列消息
                case PayConstants.Wechat.TRADE_CLOSED:
                    if (result.getPayer() != null) {
                        queryOrderPayResponse.setPayerInfo(StringUtils.trimToEmpty(result.getPayer().getOpenid()));
                    }
                    queryOrderPayResponse.setPayStatusEnum(PayStatusEnum.FAIL);
                    break;
                default:
                    break;
            }
        } catch (WxPayException wxPayException) {
            // 如果支付单在微信端不存在
            if (wxPayException.getErrCode().equals(PayConstants.Wechat.ORDER_NOT_EXIST) ||
                    wxPayException.getErrCode().equals(PayConstants.Wechat.ORDERNOTEXIST)) {
                queryOrderPayResponse = new InternalPayQueryResponse();
                queryOrderPayResponse.setPayStatusEnum(PayStatusEnum.FAIL);
            }
        }
        return queryOrderPayResponse;
    }

    @Override
    public boolean verifySign(Map<String, String> params) {
        return true;
    }

    @Override
    public PayChannelEnum getChannel() {
        return PayChannelEnum.WEI_XIN;
    }

    @Override
    public String getLogo() {
        return "/img/wechat-pay.jpg";
    }
}
